package com.lm.stream;

import com.alibaba.fastjson.JSONArray;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import org.junit.Test;

import java.time.LocalDate;
import java.time.Period;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @Auther: Min.Liu
 * @Description:
 * @Date: Created in 11:48 2024/5/8
 */
public class StreamTest {

    private static void common() {
        //一. 流的常用创建方法
        //1.1
//        List<String> list = new ArrayList<>();
//        Stream<String> stream = list.stream(); //获取一个顺序流
//        Stream<String> parallelStream = list.parallelStream(); //获取一个并行流
        //1.2
//        Integer[] nums = new Integer[10];
//        Stream<Integer> Arrstream = Arrays.stream(nums);
        //1.3
        // 1. of()
        Stream<Integer> streambyof = Stream.of(1, 2, 3, 4, 5, 6);
        // 2. iterate()
        Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 2).limit(6);
        stream2.forEach(System.out::println); // 0 2 4 6 8 10
        // 3. generate()
        Stream<Double> stream3 = Stream.generate(Math::random).limit(2);
        stream3.forEach(System.out::println);
// 实例：集合内元素>5,去重，跳过前两位，取剩下元素的两个返回为新集合
        Stream<Integer> stream = Stream.of(6, 4, 6, 7, 3, 9, 8, 10, 12, 14, 14);
        Stream<Integer> newStream = stream.filter(s -> s > 5) //6 6 7 9 8 10 12 14 14
                .distinct() //6 7 9 8 10 12 14
                .skip(2) //9 8 10 12 14
                .limit(2); //9 8
        newStream.forEach(System.out::println);

        // 1. Map可以看成一个转换器，传入一个对象，返回新的对象
// map的使用实例   stream.map(x->x.getId());
        List<String> list = Arrays.asList("a,b,c", "1,2,3");
// 去掉字符串中所有的,
        List<String> collect = list.stream().map(s -> s.replaceAll(",", "")).collect(Collectors.toList());
// collect集合内容为：{abc,123}
        System.out.println(collect);

// 2. flatMap   效果：结果展平 ，即把嵌套集合，按照子集合的形式，统一放入到新的一个集合中
//				接收一个函数作为参数，将流中的每个值都换成另一个流，
//				然后把所有流连接成一个流。
        Stream<String> stringStream = list.stream().flatMap(s -> {
            // 将字符串以,分割后得到一个字符串数组
            String[] split = s.split(",");
            // 然后将每个字符串数组对应流返回，flatMap会自动把返回的所有流连接成一个流
            Stream<String> mystream = Arrays.stream(split);
            return mystream;
        });
// stringStream.collect(Collectors.toList())的集合内容为：{a,b,c,1,2,3}
        System.out.println(stringStream.collect(Collectors.toList()));
    }

    @Test
    public void test() {
        //	说明：reduce看似效果和map相似，
//			但reduce返回的是函数经过执行运算后的结果,
//			而map返回的是处理后新的集合
        List<String> memberNames = new ArrayList<>();
        memberNames.add("Amitabh");
        memberNames.add("Shekhar");
        memberNames.add("Aman");
        memberNames.add("Aman");
        memberNames.add("Rahul");
        memberNames.add("Shahrukh");
        memberNames.add("Salman");
        memberNames.add("Yana");
        memberNames.add("Lokesh");


// 将集合中的元素按照#连接成字符串，并返回放置在Optional<String>中
        Optional<String> reduced = memberNames.stream().distinct()
                .reduce((s1, s2) -> s1 + "#" + s2);
// 有值则取出打印显示
        reduced.ifPresent(System.out::println);
// 输出内容：   Amitabh#Shekhar#Aman#Rahul#Shahrukh#Salman#Yana#Lokesh

    }

    @Test
    public void test2() {
// 计算统计实例：
        /**
         * T reduce(T identity, BinaryOperator<T> accumulator);
         * identity：它允许用户提供一个循环计算的初始值。
         * accumulator：计算的累加器，
         */
        //T reduce(T identity, BinaryOperator<T> accumulator);
        System.out.println("给定个初始值，求和");
        System.out.println(Stream.of(1, 2, 3, 4).reduce(100, (sum, item) -> sum + item));
        System.out.println(Stream.of(1, 2, 3, 4).reduce(100, Integer::sum));
        // 输出：110

        System.out.println("给定个初始值，求min");
        System.out.println(Stream.of(1, 2, 3, 4).reduce(100, (min, item) -> Math.min(min, item)));
        System.out.println(Stream.of(1, 2, 3, 4).reduce(100, Integer::min));
        // 输出：1

        System.out.println("给定个初始值，求max");
        System.out.println(Stream.of(1, 2, 3, 4).reduce(100, (max, item) -> Math.max(max, item)));
        System.out.println(Stream.of(1, 2, 3, 4).reduce(100, Integer::max));
        // 输出：100

        //Optional<T> reduce(BinaryOperator<T> accumulator);
        // 注意返回值，上面的返回是T,泛型，传进去啥类型，返回就是啥类型。
        // 下面的返回的则是Optional类型
        System.out.println("无初始值，求和");
        System.out.println(Stream.of(1, 2, 3, 4).reduce(Integer::sum).orElse(0));
        // 输出：10
        Integer sum = Stream.of(1, 2, 3, 4).reduce((x, y) -> x + y).get();
        System.out.println(sum);  // 输出：10

        System.out.println("无初始值，求max");
        System.out.println(Stream.of(1, 2, 3, 4).reduce(Integer::max).orElse(0));
        // 输出：4

        System.out.println("无初始值，求min");
        System.out.println(Stream.of(1, 2, 3, 4).reduce(Integer::min).orElse(0));
        // 输出：1


        // 按照默认字典顺序排序
        Stream.of(1, 2, 3, 4).sorted();
// 按照sortNo排序
        //  Stream.of(1, 2, 3, 4).sorted((x, y) -> Integer.compare(x.getSortNo(), y.getSortNo()));

        // 正向排序（默认）
        //pendingPeriod.stream().sorted(Comparator.comparingInt(ReservoirPeriodResult::getId));
// 逆向排序
        //pendingPeriod.stream().sorted(Comparator.comparingInt(ReservoirPeriodResult::getId).reversed());

    }

    @Test
    public void test3() {
        // 准备测试数据
//        Stream<DateModel> stream = Stream.of(new DateModel(LocalDate.of(2020, 1, 1))
//                , new DateModel(LocalDate.of(2021, 1, 1)), new DateModel(LocalDate.of(2022, 1, 1)));

// 正向排序（默认）
//        stream.sorted(Comparator.comparing(DateModel::getLocalDate))
//                .forEach(System.out::println);
// 逆向排序
//        stream.sorted(Comparator.comparing(DateModel::getLocalDate).reversed())
//                .forEach(System.out::println);
    }

    //	默认返回类型为HashMap，可通过Collectors.toCollection(LinkedHashMap::new)
//		显示指明使用其它数据结构作为返回值容器

    // 测试实体类
    @Data
    public class Entity {
        private Integer id;
        private String name;

        public Entity(int id, String name) {
            this.id = id;
            this.name = name;
        }
    }


    @Test
    public void test4() {
        // 模拟从数据库中查询批量的数据
        List<Entity> entityList = Stream.of(new Entity(1, "A"),
                new Entity(2, "B"), new Entity(3, "C")).collect(Collectors.toList());

        // 将集合数据转化成id与name的Map
        entityList.stream()
                .collect(Collectors.toMap(Entity::getId, Entity::getName)).forEach((k, v) -> {
            System.out.println(k + v);
        });

    }

    public static <E> E toObject(Collection<E> collection) {
        // 处理集合空指针异常
        Collection<E> coll = Optional.ofNullable(collection).orElseGet(ArrayList::new);
        // 此处可以对流进行排序，然后取出第一个元素
        return coll.stream().findFirst().orElse(null);
    }

    @Data
    public static class Org {
        private Integer id;
        private String num;
        private LocalDate date;
        private Double amt;
        private String status;
//        @JsonProperty
//        private Integer id;
//        @JsonProperty
//        private String num;
//        @JsonProperty
//        private LocalDate date;
//        @JsonProperty
//        private Double amt;
//        @JsonProperty
//        private String status;

        @JsonCreator
        public Org(@JsonProperty("id") int id, @JsonProperty("num") String num, @JsonProperty("date") LocalDate date, @JsonProperty("amt") double amt, @JsonProperty("status") String status) {
            this.id = id;
            this.num = num;
            this.date = date;
            this.amt = amt;
            this.status = status;
        }

//        public Org() {
//        }

//        public Org(int id,String num,LocalDate date, double amt, String status) {
//            this.id = id;
//            this.num = num;
//            this.date = date;
//            this.amt = amt;
//            this.status = status;
//        }


    }


    @Test
    public void test5() {
        List<Org> xOrgs = new ArrayList<>();
        xOrgs.add(new Org(1, "s1", LocalDate.of(2021, 3, 05), 30000d, "2"));
        xOrgs.add(new Org(2, "s1", LocalDate.of(2021, 3, 04), 200000d, "1"));
        xOrgs.add(new Org(3, "s2", LocalDate.of(2022, 1, 22), 100000d, "1"));
        xOrgs.add(new Org(4, "s2", LocalDate.of(2023, 9, 15), 30000d, "1"));
        xOrgs.add(new Org(5, "s3", LocalDate.of(2022, 7, 22), 100000d, "1"));
        xOrgs.add(new Org(6, "s3", LocalDate.of(2023, 9, 15), 500000d, "1"));
        xOrgs.add(new Org(7, "s3", LocalDate.of(2021, 1, 15), 500000d, "2"));
        xOrgs.add(new Org(8, "s4", LocalDate.of(2020, 11, 11), 200000d, "1"));
        xOrgs.add(new Org(8, "s5", LocalDate.of(2021, 11, 13), 1000000d, "1"));
        xOrgs.add(new Org(8, "s5", LocalDate.of(2020, 11, 13), 1000000d, "2"));
        // 默认使用List作为分组后承载容器
        Map<String, List<Org>> hashMap =
                xOrgs.stream().collect(Collectors.groupingBy(Org::getNum));
        hashMap.forEach((k, v) -> System.out.println(k + ":" + v.toString()));

        LocalDate now = LocalDate.now();
        ArrayList<String> rmlist = new ArrayList<>();
        for (String key : hashMap.keySet()) {
            List<Org> list = hashMap.get(key);
            Optional<Org> min = list.stream().min(Comparator.comparingLong(p -> p.getDate().toEpochDay()));
            if (diffInMonths(min.get().getDate(), now) < 12 * 3) {
                rmlist.add(key);
            }
        }
        for (String s : rmlist) {
            hashMap.remove(s);
        }
        System.out.println("删除后==================");
//        for (Map.Entry<String, List<Org>> entry : hashMap.entrySet()) {
//            List<Org> list = entry.getValue();
//            Optional<Org> min = list.stream().min(Comparator.comparingLong(p -> p.getDate().toEpochDay()));
//           // Optional<Org> min = list.stream().reduce((s1,s2)->Math.min(s1));
//           // Optional<LocalDate> min = list.stream().map(s -> s.date).min(Comparator.comparingLong(p -> p.toEpochDay()));
//            if(diffInMonths(min.get().getDate(),now)<12*3){
//                System.out.println("需要删除的"+entry.getKey());
//          //  if(diffInMonths(min.get(),now)>12*3){
//            //    hashMap.remove(entry.getKey());
//            }
//        }
        hashMap.forEach((k, v) -> {
            System.out.println(k + ":" + v.toString());
        });
        ArrayList<Org> orginfos = new ArrayList<>();
        for (Map.Entry<String, List<Org>> entry : hashMap.entrySet()) {
            List<Org> list = entry.getValue();
            orginfos.addAll(list);
        }
        List<Org> orgList = orginfos.stream().filter(org ->
                org.status != null && org.status.equals("1")
        ).collect(Collectors.toList());
        System.out.println(orgList);
        System.out.println("++++++++++++++++++++++++++");
        System.out.println(JSONArray.toJSONString(orgList));
        Long count = orginfos.stream().filter(org ->
                org.status != null && org.status.equals("1")
        ).count();

        Optional<Double> sumAmt = orginfos.stream().filter(org ->
                org.status != null && org.status.equals("1")
        ).map(s -> s.amt).reduce((s1, s2) -> s1 + s2);
        Optional<Double> MaxAmt = orginfos.stream().filter(org ->
                org.status != null && org.status.equals("1")
        ).map(s -> s.amt).max(Comparator.comparingDouble(s -> s));
        System.out.println("总条数:" + count);
        System.out.println("总金额:" + sumAmt.get());
        System.out.println("平均金额:" + sumAmt.get() / count);
        System.out.println("最大金额:" + MaxAmt.get());
    }

    private static int diffInMonths(LocalDate begin, LocalDate end) {
        if (begin != null && end != null) {
            return Period.between(begin, end).getYears() * 12 + Period.between(begin, end).getMonths();
        }
        return 0;
    }

    @Test
    public void Test7() {
        LocalDate date = LocalDate.of(2021, 11, 13);
        LocalDate now = LocalDate.now();
        System.out.println(diffInMonths(date, now));
        System.out.println(diffInMonths(now, date));
    }


    @Test
    public void Test8() {
//        List<String> list2 = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu");
//        Entity entity1 = new Entity(1,"liumin");
//        Entity entity2 = new Entity(2,"limengli");
//        Entity entity3 = new Entity(3,"liushuyi");
        Entity entity4 = new Entity(1, "liuting");
//        List<Entity> list = Arrays.asList(entity1,entity2,entity3);
//        list.stream().limit(2).forEach(System.out::println);
//        list2.stream().collect(Collectors.joining());
//
        Optional<Entity> optional = Optional.of(entity4);
//        Stream.generate(Math::random).limit(2).forEach(System.out::println);
//        IntStream.range(2,8).limit(2).forEach(System.out::println);
//
//
//        String[] strings = list2.stream().toArray(String[]::new);
//        List<String> collect = list2.stream().collect(Collectors.toList());
//        List<String> collect2 = list2.stream().collect(Collectors.toCollection(LinkedList::new));
//        HashSet<Object> collect1 = list2.stream().collect(HashSet::new, HashSet::add, HashSet::addAll);
//        //类型推导
//        list2.stream().collect((Supplier<Set<String>>) HashSet::new, Set::add, Set::addAll);

        List<String> list3 = Arrays.asList("a,b,c", "1,2,3");
        list3.stream().flatMap(s -> Stream.of(s.split(","))).forEach(System.out::println);

    }


    @Data
    public static class myOrg {
        private Integer id;
        private String num;
        private LocalDate date;
        private Double amt;
        private Double pmt;
        private String status;

        @JsonCreator
        public myOrg(@JsonProperty("id") int id, @JsonProperty("num") String num, @JsonProperty("date") LocalDate date, @JsonProperty("amt") double pmt, @JsonProperty("amt") double amt, @JsonProperty("status") String status) {
            this.id = id;
            this.num = num;
            this.date = date;
            this.amt = amt;
            this.pmt = pmt;
            this.status = status;
        }

        @Override
        public String toString() {
            return "myOrg{" +
                    "id=" + id +
                    ", num='" + num + '\'' +
                    ", date=" + date +
                    ", amt=" + amt +
                    ", pmt=" + pmt +
                    ", status='" + status + '\'' +
                    '}';
        }
    }

    @Test
    public void Test9() {
        List<myOrg> xOrgs = new ArrayList<myOrg>();
        xOrgs.add(new myOrg(1, "s1", LocalDate.of(2020, 2, 05), 60000d, 30000d, "2"));
        xOrgs.add(new myOrg(2, "s1", LocalDate.of(2021, 3, 04), 60000d, 200000d, "1"));
        xOrgs.add(new myOrg(3, "s2", LocalDate.of(2022, 1, 22), 60000d, 100000d, "1"));
        xOrgs.add(new myOrg(4, "s2", LocalDate.of(2023, 9, 15), 30000d, 500000d, "1"));
        xOrgs.add(new myOrg(5, "s3", LocalDate.of(2022, 7, 22), 30000d, 100000d, "1"));
        xOrgs.add(new myOrg(6, "s3", LocalDate.of(2023, 9, 15), 40000d, 500000d, "1"));
        xOrgs.add(new myOrg(7, "s3", LocalDate.of(2021, 1, 15), 40000d, 600000d, "2"));
        xOrgs.add(new myOrg(8, "s4", LocalDate.of(2020, 11, 11), 30000d, 20000d, "1"));
        xOrgs.add(new myOrg(8, "s5", LocalDate.of(2021, 11, 13), 30000d, 1000000d, "1"));
        xOrgs.add(new myOrg(8, "s5", LocalDate.of(2020, 11, 13), 30000d, 1000000d, "2"));


        List<myOrg> list2 = xOrgs.stream().sorted((s1, s2) -> (int) (s1.getAmt() - s2.getAmt())).collect(Collectors.toList());
        for (myOrg org : list2) {
            System.out.println(org);
        }

//        Map<String, List<myOrg>> listMap = xOrgs.stream().sorted((s1, s2) -> {
//            if (s1.getPmt()!=s2.getPmt()) {
//                return (int) (s1.getPmt() - s2.getPmt());
//            }else{
//                return (int) (s1.getAmt() - s2.getAmt());
//            }
//        }).collect(Collectors.groupingBy((myOrg s)->s.getPmt()+"#"+s.getAmt(), LinkedHashMap::new, Collectors.toList()));


//        Map<Double, List<myOrg>> listMap = xOrgs.stream().sorted((s1, s2) -> {
//            if (!s1.getPmt().equals(s2.getPmt())) {
//                return (int) (s1.getPmt() - s2.getPmt());
//            }else{
//                return (int) (s1.getAmt() - s2.getAmt());
//            }
//        }).collect(Collectors.groupingBy((myOrg s)->s.getPmt(), LinkedHashMap::new, Collectors.toList()));
//        for (Double s : listMap.keySet()) {
//            System.out.println(s);
//            if (listMap.get(s).size()>1) {
//                for (myOrg myOrg : listMap.get(s)) {
//                    System.out.println(myOrg);
//                }
//            }
//        }

//        List<Org> list2 = list.stream().sorted((s1, s2) -> {
//            return s1.getAmt() - s2.getAmt() > 0 ? 1 : -1;
//        }).collect(Collectors.toList());
//        for (String s : listMap.keySet()) {
//            System.out.println(s);
//            if (listMap.get(s).size()>1) {
//                for (myOrg myOrg : listMap.get(s)) {
//                    System.out.println(myOrg);
//                }
//            }
//        }


    }


}
